package qc.module.platform.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.enums.DataTypeEnum;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.pair.KeyValuePairDto;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.module.platform.dto.param.group.ParamGroupDto;
import qc.module.platform.dto.param.group.ParamGroupQueryConditionDto;
import qc.module.platform.dto.param.item.ParamItemDto;
import qc.module.platform.dto.param.item.ParamItemQueryConditionDto;
import qc.module.platform.dto.param.item.ParamOptionsDto;
import qc.module.platform.entity.QcParamGroup;
import qc.module.platform.entity.QcParamItem;
import qc.module.platform.mapper.ParamGroupMapper;
import qc.module.platform.mapper.ParamItemMapper;
import qc.module.platform.repository.QcParamGroupRepository;
import qc.module.platform.repository.QcParamItemRepository;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * ParamService
 *
 * @author QuCheng Tech
 * @since 2024/2/21
 */
@Service
public class ParamService {
    private QcParamGroupRepository groupRepository;
    private QcParamItemRepository itemRepository;
    
    @Autowired
    private DbTableService dbTableService;

    @Autowired
    public void setQcParamGroupRepository(QcParamGroupRepository groupRepository) {
        this.groupRepository = groupRepository;
    }

    @Autowired
    public void setQcParamItemRepository(QcParamItemRepository itemRepository) {
        this.itemRepository = itemRepository;
    }

    /**
     * 根据关键字查询参数分组信息列表
     * @param conditionDto 关键字，匹配分组编码、分组名称、数据库表编码
     * @return 参数分组信息集合
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public List<ParamGroupDto> queryGroup(ParamGroupQueryConditionDto conditionDto){
        LambdaQueryWrapper<QcParamGroup> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(conditionDto.getKeywords())){
            wrapper.and(p -> {
                p.like(QcParamGroup::getCode,conditionDto.getKeywords()).or()
                        .like(QcParamGroup::getName,conditionDto.getKeywords()).or()
                        .like(QcParamGroup::getTablecode,conditionDto.getKeywords());
            });
        }

        List<QcParamGroup> ens = groupRepository.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(ens)) return ParamGroupMapper.MAPPER.toDtoList(ens);
        return null;
    }
    
    /***
     * 获取指定参数分组信息
     *
     * @param paramGroupCode 参数分组编码
     * @return qc.module.platform.dto.param.group.ParamGroupDto
     * @author QuCheng Tech
     * @since 2024/2/21
     */
    public ParamGroupDto getGroup(String paramGroupCode) throws QCPromptException {
        if (StringUtils.isEmpty(paramGroupCode))
            throw new QCPromptException("获取指定参数分组的参数值信息时，参数分组编码不能为空");

        LambdaQueryWrapper<QcParamGroup> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(QcParamGroup::getCode, paramGroupCode);

        QcParamGroup en = groupRepository.selectOne(wrapper);
        if (en != null)
            return ParamGroupMapper.MAPPER.toDto(en);

        return null;
    }

    /**
     * 新增参数分组
     * @param dto 新增参数分组对象
     * @return 成功返回null，失败返回错误信息
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public String addGroup(ParamGroupDto dto) {
        // 1.新增对象判空
        if (Objects.isNull(dto))  return QCUnifyReturnValue.Warn("新增对象不能为空");
        if (StringUtils.isBlank(dto.getCode())) return QCUnifyReturnValue.Warn("分组编码不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("分组名称不能为空");
        if (StringUtils.isBlank(dto.getTablecode())) return QCUnifyReturnValue.Warn("数据库表编码不能为空");
        
        // 2.判断数据库表编码是否存在，不存在则提示
        if (!dbTableService.isExist(dto.getTablecode())) return QCUnifyReturnValue.Warn("数据库表编码不存在");
        
        // 3.判断分组编码是否已经存在，已经存在则提示
        if (isExistGroupCode(dto.getCode())) return QCUnifyReturnValue.Warn("分组编码已经存在");
        
        // 4.dto转换为entity
        QcParamGroup en = ParamGroupMapper.MAPPER.toEntity(dto);
        
        // 5.保存数据
        if (groupRepository.insert(en) < 0x1) return QCUnifyReturnValue.Warn("新增数据失败");
        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改参数分组
     * @param dto 修改参数分组对象
     * @return 成功返回null，失败返回错误信息
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public String updateGroup(ParamGroupDto dto){
        // 1.修改对象判空
        if (Objects.isNull(dto))  return QCUnifyReturnValue.Warn("新增对象不能为空");
        if (StringUtils.isBlank(dto.getCode())) return QCUnifyReturnValue.Warn("分组编码不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("分组名称不能为空");
        if (StringUtils.isBlank(dto.getTablecode())) return QCUnifyReturnValue.Warn("数据库表编码不能为空");

        // 2.判断数据库表编码是否存在，不存在则提示
        if (!dbTableService.isExist(dto.getTablecode())) return QCUnifyReturnValue.Warn("数据库表编码不存在");

        // 3.判断分组编码是否存在，不存在则提示
        if (!isExistGroupCode(dto.getCode())) return QCUnifyReturnValue.Warn("分组编码不存在");

        // 4.dto转换为entity
        QcParamGroup en = ParamGroupMapper.MAPPER.toEntity(dto);
        
        // 5.修改数据
        groupRepository.updateById(en);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除参数分组
     * @param groupCode 参数分组编码
     * @return 成功返回null，失败返回错误信息
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public String deleteGroup(String groupCode){
        // 1.条件判空
        if (StringUtils.isBlank(groupCode)) return QCUnifyReturnValue.Warn("参数分组编码不能为空");
        
        // 2.判断指定删除的分组编码下是否有参数项，如果有则提示
        List<QcParamItem> items = getGroupItemEntity(groupCode,false);
        if (CollectionUtils.isNotEmpty(items)) return QCUnifyReturnValue.Warn("该分组下有参数项，请先清除参数项");
        
        // 3. 删除分组
        groupRepository.deleteById(groupCode);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 获取分组参数项
     * @param conditionDto 查询条件
     * @return 指定分组参数项集合
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public List<ParamItemDto> getGroupItems(ParamItemQueryConditionDto conditionDto) throws QCPromptException {
        // 1.条件判空
        if (Objects.isNull(conditionDto)) throw new QCPromptException("查询条件不能为空");
        if (StringUtils.isBlank(conditionDto.getGroupcode())) throw new QCPromptException("分组编码不能为空");
        
        // 2.构建查询条件
        LambdaQueryWrapper<QcParamItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcParamItem::getGroupcode,conditionDto.getGroupcode());
        wrapper.orderByAsc(QcParamItem::getOdr);
        // 2.1 关键字匹配参数项编码、参数项名称
        if (StringUtils.isNotBlank(conditionDto.getKeywords())){
            wrapper.and(p -> {
                p.like(QcParamItem::getItemcode,conditionDto.getKeywords()).or()
                        .like(QcParamItem::getName,conditionDto.getKeywords());
            });
        }
        
        //3.查询数据
        List<QcParamItem> ens = itemRepository.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(ens)) return ParamItemMapper.MAPPER.toDtoList(ens);
        return null;
    }

    /**
     * 获取参数项信息
     * @param itemId 参数项ID
     * @return 参数项信息
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public ParamItemDto getItem(String itemId) throws QCPromptException {
        if (StringUtils.isBlank(itemId)) throw new QCPromptException("参数项ID不能为空");
        
        QcParamItem en = itemRepository.selectById(itemId);
        if (Objects.nonNull(en)) return ParamItemMapper.MAPPER.toDto(en);
        return null;
    }

    /**
     * 新增参数项
     * @param dto 新增对象
     * @return 成功返回null，失败返回错误信息
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public String addItem(ParamItemDto dto){
        // 1.新增对象判空
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("新增对象不能为空");
        if (StringUtils.isBlank(dto.getGroupcode())) return QCUnifyReturnValue.Warn("分组编码不能为空");
        if (StringUtils.isBlank(dto.getItemcode())) return QCUnifyReturnValue.Warn("参数项编码不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("参数项名称不能为空");
        
        // 2.判断分组编码是否存在，不存在则提示
        if (!isExistGroupCode(dto.getGroupcode())) return QCUnifyReturnValue.Warn("分组编码不存在");
        
        // 3.dto转换为entity
        QcParamItem en = ParamItemMapper.MAPPER.dtoToEntity(dto);
        
        // 4.保存数据
        if (itemRepository.insert(en) < 0x1)
            return QCUnifyReturnValue.Warn("新增数据失败");
        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改参数项
     * @param dto 修改对象
     * @return 成功返回null，失败返回错误信息
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public String updateItem( ParamItemDto dto){
        // 1.新增对象判空
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("新增对象不能为空");
        if (StringUtils.isBlank(dto.getGroupcode())) return QCUnifyReturnValue.Warn("分组编码不能为空");
        if (StringUtils.isBlank(dto.getItemcode())) return QCUnifyReturnValue.Warn("参数项编码不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("参数项名称不能为空");

        // 2.判断分组编码是否存在，不存在则提示
        if (!isExistGroupCode(dto.getGroupcode())) return QCUnifyReturnValue.Warn("分组编码不存在");
        
        // 3.判断参数项ID是否存在，不存在则提示
        if (Objects.isNull(itemRepository.selectById(dto.getId()))) return QCUnifyReturnValue.Warn("修改的参数项不存在");

        // 4.dto转换为entity
        QcParamItem en = ParamItemMapper.MAPPER.dtoToEntity(dto);
        
        // 5.修改数据
        itemRepository.updateById(en);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除参数项
     * @param itemId 参数项ID
     * @return 成功返回null，失败返回错误信息
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public String deleteItem(String itemId) throws QCPromptException {
        // 1.条件判空
        if (StringUtils.isBlank(itemId)) throw new QCPromptException("参数项ID不能为空");
        // 2.删除数据
        itemRepository.deleteById(itemId);
        return QCUnifyReturnValue.Success();
    }
    
    /***
     * 获取指定参数分组中的参数项集合，可以指定参数项的状态
     *
     * @param paramGroupCode 参数分组编码
     * @param isValid 是否有效，true表示项目必须为有效状态，false表示不管项目状态是否有效
     * @return java.util.List<qc.module.platform.entity.QcParamItem>
     * @author QuCheng Tech
     * @since 2024/2/21
     */
    public List<QcParamItem> getGroupItemEntity(String paramGroupCode, boolean isValid) {
        if (StringUtils.isNotBlank(paramGroupCode)) {
            LambdaQueryWrapper<QcParamItem> wrapper = new LambdaQueryWrapper<>();

            wrapper.eq(QcParamItem::getGroupcode, paramGroupCode);
            if (isValid)
                wrapper.eq(QcParamItem::getFlag, ResourceStatusFlagEnum.NORMAL);

            //排序，先按排序号，再按参数项名称
            wrapper.orderByAsc(QcParamItem::getOdr);
            wrapper.orderByAsc(QcParamItem::getName);

            //查询
            return itemRepository.selectList(wrapper);
        }

        return null;
    }

    /**
     * 返回参数项的数据选择项集合
     * @return ParamOptionsDto
     * @author QuCheng Tech
     * @since 2024/4/15
     */
    public ParamOptionsDto getOptions(){
        ParamOptionsDto paramOptionsDto = new ParamOptionsDto();

        //处理列的数据类型选择项
        List<KeyValuePairDto> datatypeOptions = new ArrayList<>();
        for (DataTypeEnum dataTypeEnum : DataTypeEnum.values()){
            KeyValuePairDto keyValuePairDto = new KeyValuePairDto();
            keyValuePairDto.setKey(String.valueOf(dataTypeEnum.getIndex()));
            keyValuePairDto.setValue(dataTypeEnum.getName());
            datatypeOptions.add(keyValuePairDto);
        }
        paramOptionsDto.setDatatypeOptions(datatypeOptions);
        
        return paramOptionsDto;
    }

    /**
     * 查询参数分组编码是否存在
     * @param groupCode 分组编码
     * @return 存在返回true，否则返回false
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    private boolean isExistGroupCode(String groupCode){
        if (Objects.nonNull(groupRepository.selectById(groupCode))) 
            return true;
        return false;
    }
}
